import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.PriorityQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class VoronoiGUI {

	class IscrtaniPanel extends JPanel {

		public void paint(Graphics g) {
			Graphics2D g2 = (Graphics2D) g;
			RenderingHints hints = new RenderingHints(
					RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
			g2.addRenderingHints(hints);
			g2.clearRect(0, 0, grafika.getWidth(), grafika.getHeight());
			g2.setColor(new Color(0, 0, 0));
			for (int i = 0; i < pocetne.size(); i++)
				g.drawRoundRect((int) pocetne.get(i).getX() - 1, (int) pocetne
						.get(i).getY() - 1, 3, 3, 2, 2);
			g2.setColor(new Color(200, 100, 100));
			if (noviDogadjaj instanceof Tacka) {
				g2.drawLine(0, (int) ((Tacka) noviDogadjaj).getY(), this
						.getWidth(), (int) ((Tacka) noviDogadjaj).getY());

				g2.setColor(new Color(100, 200, 100));
				// System.out.println(" ");
				for (Object l : stablo) {
					// System.out.println((((List)l).getPocetak() + "  " +
					// (((List)l).getKraj())));
					double xPocetak = ((List) l).getPocetak()
							- (((List) l).getTac()).getX();
					double xKraj = ((List) l).getKraj()
							- (((List) l).getTac()).getX();
					// xPocetak = -1000; xKraj = 1000;

					for (double pomeraj = xPocetak; pomeraj < xKraj; pomeraj += 0.01) {
						double p = (((Tacka)noviDogadjaj).getY() - (((List) l).getTac())
								.getY()) / 2;
						double ipsilon = pomeraj * pomeraj / (4 * p);
						double koordinataX = (((List) l).getTac()).getX()
								+ pomeraj;
						double koordinataY = (((List) l).getTac()).getY() + p
								- ipsilon;
						g2.drawRect((int) koordinataX, (int) koordinataY, 0, 0);
					}
				}
			}

			// crtam krugove
			g2.setColor(Color.RED);
			Object[] pomocniDogadjaji = dogadjaji.toArray();
			
			for (int i=0; i<pomocniDogadjaji.length; i++) {
				Dogadjaj dogadjaj = (Dogadjaj)pomocniDogadjaji[i];
				if (dogadjaj instanceof Krug) {
					Krug krug = (Krug) dogadjaj;
					g2.drawRect((int) (krug.getCentar().getX() - krug
							.getPoluprecnik()),
							(int) (krug.getCentar().getY() - krug
									.getPoluprecnik()), (int) (krug
									.getPoluprecnik() * 2), (int) (krug
									.getPoluprecnik() * 2));
				}
			}

			g2.setColor(new Color(250, 50, 50));
			for (Tacka t : preseci) {
				g2.drawRoundRect((int) t.getX() - 1, (int) t.getY() - 1, 3, 3,
						2, 2);
			}

		}
	}

	ArrayList<Tacka> pocetne;
	PriorityQueue<Dogadjaj> dogadjaji;
	ArrayList<List> stablo;
	ArrayList<Tacka> preseci;

	JFrame frejm;
	JPanel glavni, opcije;
	IscrtaniPanel grafika;
	JButton dalje;
	JLabel status;
	Dogadjaj noviDogadjaj;

	public void prikazi() {

		JFrame.setDefaultLookAndFeelDecorated(true);
		frejm = new JFrame("Voronoi dijagram");
		frejm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frejm.setPreferredSize(new Dimension(1024, 768));

		glavni = new JPanel(new BorderLayout());
		opcije = new JPanel(new GridLayout(2, 2));
		opcije.setPreferredSize(new Dimension(200, 768));
		grafika = new IscrtaniPanel();

		dalje = new JButton("Dalje");
		dalje.addActionListener(new ActionListener() {
			public synchronized void actionPerformed(ActionEvent e2) {
				if (dogadjaji.size() > 0) {
					preseci = new ArrayList<Tacka>();
					noviDogadjaj = (Dogadjaj) dogadjaji.poll();
					if (noviDogadjaj instanceof Tacka) {
						List noviList = new List((Tacka) noviDogadjaj, 0, 1000);

						Collections.sort(stablo);
						/*
						 * for (int i = 0; i<stablo.size(); i++) {
						 * stablo.get(i).setPocetak(-1000);
						 * stablo.get(i).setKraj(1000); }
						 */
						if (stablo.size() > 2) {

							for (int i = 1; i < stablo.size() - 1; i++) {
								List prethodni = stablo.get(i - 1);
								List trenutni = stablo.get(i);
								List sledeci = stablo.get(i + 1);
								dogadjaji.add(new Krug(prethodni.getTac(), trenutni.getTac(), sledeci.getTac()));
								double p1 = (((Tacka) noviDogadjaj).getY() - prethodni
										.getTac().getY()) / 2;
								double p2 = (((Tacka) noviDogadjaj).getY() - trenutni
										.getTac().getY()) / 2;
								//System.out.println(p1+" "+p2+" "+novaTacka.getY
								// (
								// )+" "+prethodni.getTac().getY()+" "+trenutni.
								// getTac().getY());
								double deltaX = Math.abs(trenutni.getTac()
										.getX()
										- prethodni.getTac().getX());
								double prvoX = prethodni.getTac().getX()
										+ prvoX1(p1, p2, deltaX);
								double drugoX = prethodni.getTac().getX()
										+ drugoX1(p1, p2, deltaX);
								// double prvoY =
								// novaTacka.getY()-p1-((prvoX1(p1, p2,
								// deltaX)*prvoX1(p1, p2, deltaX))/(4*p1));
								/*
								 * double drugoY =
								 * novaTacka.getY()-p2-((drugoX1(p1, p2,
								 * deltaX)drugoX1(p1, p2, deltaX))/(4p2));
								 * System
								 * .out.println(prvoX+" "+drugoX+" "+prvoY+
								 * " "+" "+drugoY+" "+p1+" "+p2);
								 * preseci.add(new Tacka(prvoX, prvoY));
								 * preseci.add(new Tacka(drugoX, drugoY));
								 */
								if (prvoX > drugoX) {
									if (prethodni.getTac().getY() > trenutni
											.getTac().getY()) {
										trenutni.setPocetak(prvoX);
										prethodni.setKraj(prvoX);
										prethodni.setPocetak(drugoX);
										System.out
												.println("prvo>drugo, prethodni>trenutni");
									} else {
										prethodni.setKraj(drugoX);
										trenutni.setKraj(prvoX);
										trenutni.setPocetak(prvoX);
										System.out
												.println("prvo>drugo, prethodni<trenutni");
									}
								} else {
									if (prethodni.getTac().getY() > trenutni
											.getTac().getY()) {
										trenutni.setPocetak(drugoX);
										prethodni.setKraj(drugoX);
										prethodni.setPocetak(prvoX);
										System.out
												.println("prvo<drugo, prethodni>trenutni");
									} else {
										prethodni.setKraj(prvoX);
										trenutni.setKraj(drugoX);
										trenutni.setPocetak(prvoX);
										System.out
												.println("prvo<drugo, prethodni<trenutni");
									}
								}
								/*
								 * p1 =
								 * (novaTacka.getY()-trenutni.getTac().getY(
								 * ))/2; p2 =
								 * (novaTacka.getY()-sledeci.getTac().getY())/2;
								 * /
								 * /System.out.println(p1+" "+p2+" "+novaTacka.getY
								 * (
								 * )+" "+trenutni.getTac().getY()+" "+sledeci.getTac
								 * ().getY()); deltaX =
								 * Math.abs(sledeci.getTac().getX() -
								 * trenutni.getTac().getX()); prvoX =
								 * trenutni.getTac().getX() + prvoX1(p1, p2,
								 * deltaX); drugoX = trenutni.getTac().getX() +
								 * drugoX1(p1, p2, deltaX); if (prvoX>drugoX) {
								 * if
								 * (prethodni.getTac().getY()>sledeci.getTac().
								 * getY()) { sledeci.setPocetak(prvoX);
								 * trenutni.setKraj(prvoX);
								 * trenutni.setPocetak(drugoX);
								 * System.out.println
								 * ("prvo>drugo, prethodni<trenutni"); } else {
								 * trenutni.setKraj(drugoX);
								 * sledeci.setKraj(prvoX);
								 * sledeci.setPocetak(prvoX);
								 * System.out.println(
								 * "prvo>drugo, prethodni>trenutni"); } } else {
								 * if
								 * (trenutni.getTac().getY()>sledeci.getTac().getY
								 * ()) { sledeci.setPocetak(drugoX);
								 * trenutni.setKraj(drugoX);
								 * trenutni.setPocetak(prvoX);
								 * System.out.println
								 * ("prvo<drugo, prethodni<trenutni"); } else {
								 * trenutni.setKraj(prvoX);
								 * sledeci.setKraj(drugoX);
								 * sledeci.setPocetak(prvoX);
								 * System.out.println(
								 * "prvo<drugo, prethodni>trenutni"); } }
								 */
							}

						} else if (stablo.size() == 2) {
							List prethodni = stablo.get(0);
							List trenutni = stablo.get(1);
							/*
							 * if
							 * (prethodni.getTac().getX()>trenutni.getTac().getX
							 * ()) { List temp = prethodni; prethodni =
							 * trenutni; trenutni = temp; }
							 */

							double p1 = (((Tacka) noviDogadjaj).getY() - prethodni
									.getTac().getY()) / 2;
							double p2 = (((Tacka) noviDogadjaj).getY() - trenutni
									.getTac().getY()) / 2;
							//System.out.println(p1+" "+p2+" "+novaTacka.getY()+
							// " "
							// +prethodni.getTac().getY()+" "+trenutni.getTac(
							// ).getY());
							double deltaX = Math.abs(trenutni.getTac().getX()
									- prethodni.getTac().getX());
							double prvoX = prethodni.getTac().getX()
									+ prvoX1(p1, p2, deltaX);
							double drugoX = prethodni.getTac().getX()
									+ drugoX1(p1, p2, deltaX);
							if (prvoX > drugoX) {
								if (prethodni.getTac().getY() > trenutni
										.getTac().getY()) {
									trenutni.setPocetak(prvoX);
									prethodni.setKraj(prvoX);
									prethodni.setPocetak(drugoX);
									System.out
											.println("prvo>drugo, prethodni<trenutni");
								} else {
									prethodni.setKraj(drugoX);
									trenutni.setKraj(prvoX);
									trenutni.setPocetak(prvoX);
									System.out
											.println("prvo>drugo, prethodni>trenutni");
								}
							} else {
								if (prethodni.getTac().getY() > trenutni
										.getTac().getY()) {
									trenutni.setPocetak(drugoX);
									prethodni.setKraj(drugoX);
									prethodni.setPocetak(prvoX);
									System.out
											.println("prvo<drugo, prethodni<trenutni");
								} else {
									prethodni.setKraj(prvoX);
									trenutni.setKraj(drugoX);
									trenutni.setPocetak(prvoX);
									System.out
											.println("prvo<drugo, prethodni>trenutni");
								}
							}
						}
						stablo.add(noviList);
					}
					// System.out.println("dodajem");
					frejm.repaint();
				} else {
					dalje.setEnabled(false);
					status.setText("Gotovo");
				}
			}
		});
		status = new JLabel("pritisnite Dalje za sledeci korak");

		pocetne = new ArrayList<Tacka>();
		napraviPocetne(pocetne, 15, 550.0, 550.0);
		Collections.sort(pocetne);

		dogadjaji = new PriorityQueue<Dogadjaj>(pocetne);
		noviDogadjaj = (Tacka) dogadjaji.poll();

		stablo = new ArrayList<List>();
		preseci = new ArrayList<Tacka>();
		if (noviDogadjaj instanceof Tacka)
			stablo.add(new List((Tacka) noviDogadjaj));

		opcije.add(dalje);
		opcije.add(status);
		glavni.add(opcije, BorderLayout.WEST);
		glavni.add(grafika, BorderLayout.CENTER);
		frejm.getContentPane().add(glavni);
		frejm.pack();
		frejm.setVisible(true);

	}

	public void napraviPocetne(ArrayList<Tacka> pocetne, int n, double maxX,
			double maxY) {
		for (int i = 0; i < n; i++) {
			Tacka pom1 = new Tacka(Math.random() * maxX + 100, Math.random()
					* maxY + 100);
			pocetne.add(pom1);
		}
	}

	public double racunajA(double p1, double p2, double deltaX) {
		return p2 - p1;
	}

	public double racunajB(double p1, double p2, double deltaX) {
		return 2 * deltaX * p1;
	}

	public double racunajC(double p1, double p2, double deltaX) {
		return 4 * p1 * p1 * p2 - 4 * p1 * p2 * p2 - deltaX * deltaX * p1;
	}

	public double prvoX1(double p1, double p2, double deltaX) {
		double a = racunajA(p1, p2, deltaX);
		double b = racunajB(p1, p2, deltaX);
		double c = racunajC(p1, p2, deltaX);
		return ((-b) + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
	}

	public double drugoX1(double p1, double p2, double deltaX) {
		double a = racunajA(p1, p2, deltaX);
		double b = racunajB(p1, p2, deltaX);
		double c = racunajC(p1, p2, deltaX);
		return ((-b) - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
	}

	public static void main(String args[]) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				VoronoiGUI gui = new VoronoiGUI();
				gui.prikazi();

			}
		});
	}
}
